import { Trans, t } from "@lingui/macro";
import TooltipComponent from "components/Tooltip/Tooltip";
import { useMemo } from "react";
import useSWR from "swr";

import { ethers } from "ethers";

import { BASIS_POINTS_DIVISOR_BIGINT } from "config/factors";
import { useGmxPrice, useTotalGmxInLiquidity, useTotalGmxStaked, useTotalGmxSupply } from "domain/legacy";

import { getContract } from "config/contracts";

import GlpManager from "abis/GlpManager.json";
import ReaderV2 from "abis/ReaderV2.json";
import Footer from "components/Footer/Footer";

import "./DashboardV2.css";

import SEO from "components/Common/SEO";
import ExternalLink from "components/ExternalLink/ExternalLink";
import InteractivePieChart from "components/InteractivePieChart/InteractivePieChart";
import PageTitle from "components/PageTitle/PageTitle";
import ChainsStatsTooltipRow from "components/StatsTooltip/ChainsStatsTooltipRow";
import StatsTooltipRow from "components/StatsTooltip/StatsTooltipRow";
import { MarketsList } from "components/Synthetics/MarketsList/MarketsList";
import { ARBITRUM, getChainName } from "config/chains";
import { getIsSyntheticsSupported } from "config/features";
import { getIcons } from "config/icons";
import { TOKEN_COLOR_MAP, getWhitelistedV1Tokens } from "config/tokens";
import { SyntheticsStateContextProvider } from "context/SyntheticsStateContext/SyntheticsStateContextProvider";
import { useFeesSummary } from "domain/stats";
import {
  getMarketIndexName,
  getMarketPoolName,
  useMarketTokensData,
  useMarketsInfoRequest,
} from "domain/synthetics/markets";
import useV2Stats from "domain/synthetics/stats/useV2Stats";
import { convertToUsd } from "domain/synthetics/tokens";
import { useInfoTokens } from "domain/tokens";
import { useChainId } from "lib/chains";
import { contractFetcher } from "lib/contracts";
import { formatDate } from "lib/dates";
import {
  BN_ZERO,
  expandDecimals,
  formatAmount,
  formatTokenAmount,
  formatUsd,
  numberWithCommas,
} from "lib/numbers";
import { EMPTY_OBJECT } from "lib/objects";
import useWallet from "lib/wallets/useWallet";
import { groupBy } from "lodash";
import AssetDropdown from "./AssetDropdown";
import { bigMath } from "lib/bigmath";
import { getPageTitle, GLP_DECIMALS, GMX_DECIMALS, USD_DECIMALS } from "lib/legacy";

const { ZeroAddress } = ethers;

export default function DashboardV2() {
  const { active, signer } = useWallet();
  const { chainId } = useChainId();

  const arbitrumOverview = useV2Stats(ARBITRUM);
  const v2MarketsOverview = useMemo(
    () => ({
      [ARBITRUM]: arbitrumOverview,
    }),
    [arbitrumOverview]
  );
  const currentV2MarketOverview = v2MarketsOverview[chainId];
  const chainName = getChainName(chainId);
  const currentIcons = getIcons(chainId);

  let { total: totalGmxSupply } = useTotalGmxSupply();

  const whitelistedTokens = getWhitelistedV1Tokens(chainId);
  const tokenList = whitelistedTokens.filter((t) => !t.isWrapped);

  const readerAddress = getContract(chainId, "Reader");
  const glpManagerAddress = getContract(chainId, "GlpManager");

  const gmxAddress = getContract(chainId, "GMX");
  const glpAddress = getContract(chainId, "GLP");
  const usdgAddress = getContract(chainId, "USDG");

  const tokensForSupplyQuery = [gmxAddress, glpAddress, usdgAddress];

  const { data: aums } = useSWR([`Dashboard:getAums:${active}`, chainId, glpManagerAddress, "getAums"], {
    fetcher: contractFetcher(signer, GlpManager),
  });

  const { data: totalSupplies } = useSWR(
    [`Dashboard:totalSupplies:${active}`, chainId, readerAddress, "getTokenBalancesWithSupplies", ZeroAddress],
    {
      fetcher: contractFetcher(signer, ReaderV2, [tokensForSupplyQuery]),
    }
  );

  const { infoTokens } = useInfoTokens(signer, chainId, active, undefined, undefined);

  const { data: feesSummaryByChain } = useFeesSummary();
  const feesSummary = feesSummaryByChain[chainId];

  const { gmxPrice, gmxPriceFromArbitrum } = useGmxPrice(
    chainId,
    { arbitrum: chainId === ARBITRUM ? signer : undefined },
    active
  );

  let { total: totalGmxInLiquidity } = useTotalGmxInLiquidity();

  let { [ARBITRUM]: arbitrumStakedGmx, total: totalStakedGmx } = useTotalGmxStaked();

  let gmxMarketCap;
  if (gmxPrice !== undefined && totalGmxSupply !== undefined) {
    gmxMarketCap = bigMath.mulDiv(gmxPrice, totalGmxSupply, expandDecimals(1, GMX_DECIMALS));
  }

  let stakedGmxSupplyUsd;
  if (gmxPrice !== undefined && totalStakedGmx !== undefined) {
    stakedGmxSupplyUsd = bigMath.mulDiv(totalStakedGmx, gmxPrice, expandDecimals(1, GMX_DECIMALS));
  }

  let aum;
  if (aums && aums.length > 0) {
    aum = (aums[0] + aums[1]) / 2n;
  }

  let glpPrice;
  let glpSupply;
  let glpMarketCap;
  if (aum && totalSupplies && totalSupplies[3]) {
    glpSupply = totalSupplies[3];
    glpPrice =
      aum && aum > 0 && glpSupply > 0
        ? bigMath.mulDiv(aum, expandDecimals(1, GLP_DECIMALS), glpSupply)
        : expandDecimals(1, USD_DECIMALS);
    glpMarketCap = bigMath.mulDiv(glpPrice, glpSupply, expandDecimals(1, GLP_DECIMALS));
  }

  let tvl: bigint | undefined = undefined;
  if (
    glpMarketCap !== undefined &&
    gmxPrice !== undefined &&
    totalStakedGmx !== undefined &&
    currentV2MarketOverview?.totalGMLiquidity !== undefined
  ) {
    tvl =
      glpMarketCap +
      bigMath.mulDiv(gmxPrice, totalStakedGmx, expandDecimals(1, GMX_DECIMALS)) +
      currentV2MarketOverview.totalGMLiquidity;
  }

  let adjustedUsdgSupply = BN_ZERO;

  for (let i = 0; i < tokenList.length; i++) {
    const token = tokenList[i];
    const tokenInfo = infoTokens[token.address];
    if (tokenInfo && tokenInfo.usdgAmount !== undefined) {
      adjustedUsdgSupply = adjustedUsdgSupply + tokenInfo.usdgAmount;
    }
  }

  let stakedPercent = 0;

  if (totalGmxSupply !== undefined && totalGmxSupply !== 0n && totalStakedGmx !== 0n) {
    stakedPercent = Number(bigMath.mulDiv(totalStakedGmx, 100n, totalGmxSupply));
  }

  let liquidityPercent = 0;

  if (totalGmxSupply !== undefined && totalGmxSupply !== 0n && totalGmxInLiquidity !== undefined) {
    liquidityPercent = Number(bigMath.mulDiv(totalGmxInLiquidity, 100n, totalGmxSupply));
  }

  let notStakedPercent = 100 - stakedPercent - liquidityPercent;

  const gmxDistributionData = useMemo(() => {
    let arr = [
      {
        name: t`staked`,
        value: stakedPercent,
        color: "#4353fa",
      },
      {
        name: t`in liquidity`,
        value: liquidityPercent,
        color: "#0598fa",
      },
      {
        name: t`not staked`,
        value: notStakedPercent,
        color: "#5c0af5",
      },
    ];

    return arr;
  }, [liquidityPercent, notStakedPercent, stakedPercent]);

  const totalStatsStartDate = t`01 Sep 2021`;

  const dailyVolumeEntries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview?.[ARBITRUM]?.dailyVolume,
    }),
    [v2MarketsOverview]
  );

  const openInterestEntries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview?.[ARBITRUM]?.openInterest,
    }),
    [v2MarketsOverview]
  );

  const totalLongPositionSizesEntries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview?.[ARBITRUM]?.totalLongPositionSizes,
    }),
    [v2MarketsOverview]
  );

  const totalShortPositionSizesEntries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview?.[ARBITRUM]?.totalShortPositionSizes,
    }),
    [v2MarketsOverview]
  );

  const weeklyFeesEntries = useMemo(
    () => ({
      "V2 Arbitrum": v2MarketsOverview?.[ARBITRUM]?.weeklyFees,
    }),
    [v2MarketsOverview]
  );

  const marketsOverviewEntries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview && formatAmount(v2MarketsOverview?.[ARBITRUM]?.totalFees, USD_DECIMALS, 0),
    }),
    [v2MarketsOverview]
  );

  const totalVolumeEntries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview?.[ARBITRUM]?.totalVolume,
    }),
    [v2MarketsOverview]
  );

  const uniqueUsersEnttries = useMemo(
    () => ({
      "Arbitrum": v2MarketsOverview?.[ARBITRUM]?.totalUsers,
    }),
    [v2MarketsOverview]
  );

  const stakedEntries = useMemo(
    () => ({
      "Staked on Arbitrum": arbitrumStakedGmx,
    }),
    [arbitrumStakedGmx]
  );

  return (
    <SEO title={getPageTitle(t`Dashboard`)}>
      <div className="default-container DashboardV2 page-layout">
        <PageTitle
          title={t`Stats`}
          isTop
          subtitle={
            <div>
              <Trans>
                {chainName} Total Stats start from {totalStatsStartDate}.<br /> For detailed stats:
              </Trans>{" "}
              <ExternalLink href="https://app.gmx.io/#/stats">V2 Pools Stats</ExternalLink>.
            </div>
          }
        />
        <div className="DashboardV2-content">
          <div className="DashboardV2-cards">
            <div className="App-card">
              <div className="App-card-title">
                <Trans>Overview</Trans>
              </div>
              <div className="App-card-divider"></div>
              <div className="App-card-content">
                <div className="App-card-row">
                  <div className="label">
                    <Trans>AUM</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      handle={`$${formatAmount(tvl, USD_DECIMALS, 0, true)}`}
                      position="bottom-end"
                      renderContent={() => (
                        <span>{t`Assets Under Management: GM Pools (${chainName}).`}</span>
                      )}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>GM Pools</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      handle={`$${formatAmount(currentV2MarketOverview?.totalGMLiquidity, USD_DECIMALS, 0, true)}`}
                      position="bottom-end"
                      renderContent={() => (
                        <Trans>
                          <p>GM Pools total value ({chainName}).</p>
                        </Trans>
                      )}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>24h Volume</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={`$${formatAmount(
                        v2MarketsOverview?.[chainId]?.dailyVolume,
                        USD_DECIMALS,
                        0,
                        true
                      )}`}
                      renderContent={() => <ChainsStatsTooltipRow entries={dailyVolumeEntries} />}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>Open Interest</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={`$${formatAmount(
                        v2MarketsOverview?.[chainId]?.openInterest,
                        USD_DECIMALS,
                        0,
                        true
                      )}`}
                      renderContent={() => <ChainsStatsTooltipRow entries={openInterestEntries} />}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>Long Positions</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={`$${formatAmount(
                        v2MarketsOverview?.[chainId]?.totalLongPositionSizes,
                        USD_DECIMALS,
                        0,
                        true
                      )}`}
                      renderContent={() => <ChainsStatsTooltipRow entries={totalLongPositionSizesEntries} />}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>Short Positions</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={`$${formatAmount(
                        v2MarketsOverview?.[chainId]?.totalShortPositionSizes,
                        USD_DECIMALS,
                        0,
                        true
                      )}`}
                      renderContent={() => <ChainsStatsTooltipRow entries={totalShortPositionSizesEntries} />}
                    />
                  </div>
                </div>
                {feesSummary?.lastUpdatedAt ? (
                  <div className="App-card-row">
                    <div className="label">
                      <Trans>Fees since</Trans> {formatDate(feesSummary.lastUpdatedAt)}
                    </div>
                    <div>
                      <TooltipComponent
                        position="bottom-end"
                        className="whitespace-nowrap"
                        handle={`$${formatAmount(
                          v2MarketsOverview?.[chainId]?.weeklyFees,
                          USD_DECIMALS,
                          2,
                          true
                        )}`}
                        renderContent={() => <ChainsStatsTooltipRow entries={weeklyFeesEntries} />}
                      />
                    </div>
                  </div>
                ) : null}
              </div>
            </div>
            <div className="App-card">
              <div className="App-card-title">
                <Trans>Total Stats</Trans>
              </div>
              <div className="App-card-divider"></div>
              <div className="App-card-content">
                <div className="App-card-row">
                  <div className="label">
                    <Trans>Total Fees</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={`$${numberWithCommas(
                        BigInt(formatAmount(v2MarketsOverview?.[chainId]?.totalFees ?? 0n, USD_DECIMALS, 0))
                      )}`}
                      renderContent={() => (
                        <ChainsStatsTooltipRow decimalsForConversion={0} entries={marketsOverviewEntries} />
                      )}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>Total Volume</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={`$${formatAmount(
                        v2MarketsOverview?.[chainId]?.totalVolume,
                        USD_DECIMALS,
                        0,
                        true
                      )}`}
                      renderContent={() => <ChainsStatsTooltipRow entries={totalVolumeEntries} />}
                    />
                  </div>
                </div>
                <div className="App-card-row">
                  <div className="label">
                    <Trans>Total Users</Trans>
                  </div>
                  <div>
                    <TooltipComponent
                      position="bottom-end"
                      className="whitespace-nowrap"
                      handle={formatAmount(
                        v2MarketsOverview?.[chainId]?.totalUsers,
                        0,
                        0,
                        true
                      )}
                      renderContent={() => (
                        <ChainsStatsTooltipRow showDollar={false} shouldFormat={false} entries={uniqueUsersEnttries} />
                      )}
                    />
                  </div>
                </div>
              </div>
            </div>
          </div>
          <PageTitle
            title={t`Tokens`}
            // afterTitle={<VersionSwitch className="ml-15" />}
            subtitle={
              <>
                <Trans>
                  GMX is the utility and governance token. Accrues 30% and 27% of V1 and V2 markets generated fees,
                  respectively.
                </Trans>
                <br />
                <Trans>
                  GM is the liquidity provider token for GMX V2 markets. Accrues 63% of the V2 markets generated fees.
                </Trans>
              </>
            }
          />
          <div className="DashboardV2-token-cards">
            <div className="stats-wrapper stats-wrapper--gmx">
              <div className="App-card">
                <div className="stats-block">
                  <div className="App-card-title">
                    <div className="App-card-title-mark">
                      <div className="App-card-title-mark-icon">
                        <img src={currentIcons.gmx} width="40" alt="GMX Token Icon" />
                      </div>
                      <div className="App-card-title-mark-info">
                        <div className="App-card-title-mark-title">GMX</div>
                        <div className="App-card-title-mark-subtitle">GMX</div>
                      </div>
                      <div>
                        <AssetDropdown assetSymbol="GMX" />
                      </div>
                    </div>
                  </div>
                  <div className="App-card-divider"></div>
                  <div className="App-card-content">
                    <div className="App-card-row">
                      <div className="label">
                        <Trans>Price</Trans>
                      </div>
                      <div>
                        {gmxPrice === 0n && "..."}
                        {gmxPrice !== 0n && (
                          <TooltipComponent
                            position="bottom-end"
                            className="whitespace-nowrap"
                            handle={"$" + formatAmount(gmxPrice, USD_DECIMALS, 2, true)}
                            renderContent={() => (
                              <>
                                <StatsTooltipRow
                                  label={t`Price on Arbitrum`}
                                  value={formatAmount(gmxPriceFromArbitrum, USD_DECIMALS, 2, true)}
                                  showDollar={true}
                                />
                              </>
                            )}
                          />
                        )}
                      </div>
                    </div>
                    <div className="App-card-row">
                      <div className="label">
                        <Trans>Supply</Trans>
                      </div>
                      <div>{formatAmount(totalGmxSupply, GMX_DECIMALS, 0, true)} GMX</div>
                    </div>
                    <div className="App-card-row">
                      <div className="label">
                        <Trans>Total Staked</Trans>
                      </div>
                      <div>
                        <TooltipComponent
                          position="bottom-end"
                          className="whitespace-nowrap"
                          handle={`$${formatAmount(stakedGmxSupplyUsd, USD_DECIMALS, 0, true)}`}
                          renderContent={() => (
                            <ChainsStatsTooltipRow
                              decimalsForConversion={GMX_DECIMALS}
                              showDollar={false}
                              entries={stakedEntries}
                            />
                          )}
                        />
                      </div>
                    </div>
                    <div className="App-card-row">
                      <div className="label">
                        <Trans>Market Cap</Trans>
                      </div>
                      <div>${formatAmount(gmxMarketCap, USD_DECIMALS, 0, true)}</div>
                    </div>
                  </div>
                </div>
                <InteractivePieChart data={gmxDistributionData} label={t`Distribution`} />
              </div>
              <GMCard />
            </div>

            {getIsSyntheticsSupported(chainId) && (
              <SyntheticsStateContextProvider skipLocalReferralCode={false} pageType="pools">
                <MarketsList />
              </SyntheticsStateContextProvider>
            )}
          </div>
        </div>
        <Footer />
      </div>
    </SEO>
  );
}

function GMCard() {
  const { chainId } = useChainId();
  const currentIcons = getIcons(chainId);
  const { marketTokensData } = useMarketTokensData(chainId, { isDeposit: true });
  const { marketsInfoData } = useMarketsInfoRequest(chainId);

  const totalGMSupply = useMemo(
    () =>
      Object.values(marketTokensData || {}).reduce(
        (acc, { totalSupply, decimals, prices }) => ({
          amount: acc.amount + (totalSupply ?? 0n),
          usd: acc.usd + (convertToUsd(totalSupply, decimals, prices?.maxPrice) ?? 0n),
        }),
        { amount: BN_ZERO, usd: BN_ZERO }
      ),
    [marketTokensData]
  );

  const chartData = useMemo(() => {
    if (totalGMSupply?.amount === undefined || totalGMSupply?.amount <= 0 || !marketsInfoData) return [];

    const poolsByIndexToken = groupBy(
      Object.values(marketsInfoData || EMPTY_OBJECT),
      (market) => market[market.isSpotOnly ? "marketTokenAddress" : "indexTokenAddress"]
    );

    return Object.values(poolsByIndexToken || EMPTY_OBJECT).map((pools) => {
      const totalMarketUSD = pools.reduce((acc, pool) => acc + pool.poolValueMax, BN_ZERO);

      const marketInfo = pools[0];
      const indexToken = marketInfo.isSpotOnly ? marketInfo.shortToken : marketInfo.indexToken;
      const marketSupplyPercentage =
        Number(bigMath.mulDiv(totalMarketUSD, BASIS_POINTS_DIVISOR_BIGINT, totalGMSupply.usd)) / 100;

      return {
        fullName: marketInfo.name,
        name: marketInfo.isSpotOnly ? getMarketPoolName(marketInfo) : getMarketIndexName(marketInfo),
        value: marketSupplyPercentage,
        color: TOKEN_COLOR_MAP[indexToken.baseSymbol ?? indexToken.symbol ?? "default"] ?? TOKEN_COLOR_MAP.default,
      };
    });
  }, [marketsInfoData, totalGMSupply]);

  return (
    <div className="App-card">
      <div className="stats-block">
        <div className="App-card-title">
          <div className="App-card-title-mark">
            <div className="App-card-title-mark-icon">
              <img src={currentIcons.gm} width="40" alt="GM Icon" />
            </div>
            <div className="App-card-title-mark-info">
              <div className="App-card-title-mark-title">GM</div>
              <div className="App-card-title-mark-subtitle">GM</div>
            </div>
            <div>
              <AssetDropdown assetSymbol="GM" />
            </div>
          </div>
        </div>
        <div className="App-card-divider"></div>
        <div className="App-card-content">
          <div className="App-card-row">
            <div className="label">
              <Trans>Supply</Trans>
            </div>

            <div>
              {formatTokenAmount(totalGMSupply?.amount, 18, "GM", {
                useCommas: true,
                fallbackToZero: true,
                displayDecimals: 0,
              })}
            </div>
          </div>
          <div className="App-card-row">
            <div className="label">
              <Trans>Market Cap</Trans>
            </div>
            <div>
              {formatUsd(totalGMSupply?.usd, {
                displayDecimals: 0,
              })}
            </div>
          </div>
        </div>
      </div>
      <InteractivePieChart data={chartData} label={t`GM Markets`} />
    </div>
  );
}
